
Celem projektu jest porównanie w zależności od problemu(regresja/klasyfikacja) różnego rodzaju modeli wraz z różnego rodzaju hiperparametrami.
● https://www.kaggle.com/uciml/red-wine-quality-cortez-et-al-2009
Team members:
Zbiór zawiera 1599 wierszy i 11 kolumn. Zmienną wynikową jest quality.
pairplot();
wykresy_pudelkowe();
wykresy_zmienne();
wykresy_zmienne_1()
analiza_korelacji()
Zbiór zawiera 240 zduplikowanych wartości. Ponieważ nie ma informacji o tym, jak pobrano próbki zestawu danych, zakładamy, że mamy do czynienia z drugim przypadkiem i dlatego zachowujemy duplikaty.
Zbiór nie zawiera brakującyh wartości
volatile acidity, citric acid,total sulfur dioxide, density, sulphates, alcohol,quality
wykres_feats()
Zbiór danych ma znacznie większą liczbę wartości 0, co wskazuje, że dane zawierają więcej wierszy, które reprezentują złą jakość wina. Zbiór jest mocno niezbalansowany.
wykres_quality()
Do niektórych modeli dane muszą być znormalizowane.
W tym celu tworzymy kopię danych, które poddajemy standaryzacji.
Model drzewa decyzyjnego i lasu losowego budowany jest na danych niestandaryzwoanych.
Ponieważ zbiór jest mocno niezrónoważony stosujemy oversampling - metody SMOTE.
wykres_plotting()
wykres_rownolegly()
wykres_odrebnosci_cech()
Ponieważ zmienna wynikowa po przekształceniu przyjmuje wartości 0 lub 1 wybraliśmy następujące modele:
Modele te zostały wybrane, żeby móc odpowiedzieć na następujące pytania:
Stworzyliśmy również model K-Means.
- Recall
- Precision
- F1
- AUC
print(classification_report(y_test, pred_test,target_names=["słabe", "dobre"]))
precision recall f1-score support
słabe 0.94 0.95 0.95 262
dobre 0.68 0.60 0.63 42
accuracy 0.90 304
macro avg 0.81 0.77 0.79 304
weighted avg 0.90 0.90 0.90 304
LABELS = ['słabe', 'dobre']
conf_matrix = confusion_matrix(y_test, pred_test)
plt.figure(figsize =(5, 5))
sns.heatmap(conf_matrix, xticklabels = LABELS,
yticklabels = LABELS, annot = True, fmt ="d");
plt.title("Confusion matrix")
plt.ylabel('True class')
plt.xlabel('Predicted class')
plt.show()
RocCurveDisplay.from_estimator(model_LR, X_test_scal, y_test);
grid_search = GridSearchCV(LogisticRegression(penalty='l2'), param_grid=params,scoring='recall',cv=5)
grid_search.fit(X_train_scal, y_train)
GridSearchCV(cv=5, estimator=LogisticRegression(),
param_grid={'C': [0.001, 0.01, 0.1, 1, 10],
'solver': ['newton-cg', 'lbfgs', 'liblinear', 'sag',
'saga']},
scoring='recall')In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook. GridSearchCV(cv=5, estimator=LogisticRegression(),
param_grid={'C': [0.001, 0.01, 0.1, 1, 10],
'solver': ['newton-cg', 'lbfgs', 'liblinear', 'sag',
'saga']},
scoring='recall')LogisticRegression()
LogisticRegression()
# Wykres ważności cech w odniesieniu do największej bezwzględnej wartości współczynnika regresji. Użyta do tej funkcja wizualizuj sama argument relative= True który powoduje że największej wartość jest przypisywana liczba
# 100 lub minus 100 a pozostałem wartością proporcjonalnie mniejsze liczby.
from yellowbrick.model_selection import FeatureImportances
fig, ax = plt.subplots (figsize=(6, 4))
fi_viz = FeatureImportances (dt)
fi_viz.fit(X, y)
fi_viz.ax.set(title="Ważność 6 cech (drzewo decyzyjne)", xlabel = "Względna ważność")
[Text(0.5, 1.0, 'Ważność 6 cech (drzewo decyzyjne)'), Text(0.5, 0, 'Względna ważność')]
import graphviz.backend as be
from dtreeviz.trees import *
viz = dtreeviz(dt, X,y,target_name="cel",feature_names=X.columns, class_names=["słabe", "dobre"],scale=(0.8))
viz
# viz.save("decision_tree.svg")
#Wykres pokazuje informacje o funkcjonowaniu drzewa. Obraz drzewa z 100 histogramami zawierającymi cenne informacje
prediction_tr = dt.predict(X_train)
prediction_ts = dt.predict(X_test)
print(sklearn.metrics.classification_report(y_test, prediction_ts, target_names=["słabe", "dobre"]))
precision recall f1-score support
słabe 0.94 0.94 0.94 262
dobre 0.60 0.60 0.60 42
accuracy 0.89 304
macro avg 0.77 0.77 0.77 304
weighted avg 0.89 0.89 0.89 304
raport_drzewo()
Jeżeli klasy nie są zrównoważone wtedy na podstawie krzywej ROC można wyciągnąć nadmiernie optymistyczne wnioski. Dlatego stosowany jest inny sposób oceniania klasyfikatora polegające na wykreśleniu krzywej Precision- Recall curve. Klasyfikacja to zrównoważony proces wyszukiwania potrzebnych danych (czułość) przy jednoczesnym ograniczeniu błędnych wyników (precyzja). Zazwyczaj trzeba znaleźć kompromis między tymi pojęciami. Im większa czułość tym mniejsza precyzja i odwrotnie.
prezycja_czulosc_drzewo()
0.5077767514532168
wykres_rownowaga_klas_drzewo()
wykres_blad_prognozowania_klas()
wykres_analiza_lime_drzewo()
plot_roc_curve(dt, X_test, y_test)
<sklearn.metrics._plot.roc_curve.RocCurveDisplay at 0x2a98d923ee0>
wykres_regresji_przy_uzyciu_drzewa()
raport_las()
#ROC_RF = plot_roc_curve(rfc, X_test, y_test)
#plt.show()
RocCurveDisplay.from_estimator(rfc, X_test, y_test);
W celu zrównoważenia danych używam oversamplingu ( metoda SMOTE). Tworzę model z parametrem sampling_strategy=0.75
ax = sns.countplot(x=y_res2)
abs_values = y_res2.value_counts().values
ax.bar_label(container=ax.containers[0], labels=abs_values);
las_po_oversamplingu()
%matplotlib inline
import seaborn as sns
sns.barplot(x=feature_imp, y=feature_imp.index)
plt.xlabel('Feature Importance Score')
plt.ylabel('Features')
plt.title("Visualizing Important Features")
#plt.legend()
plt.show()
wykres_blad_prognozowania_klas()
RocCurveDisplay.from_estimator(rfc_over2, X_test, y_test);
wykres_analiza_lime_las()
params={'criterion': ['gini','entropy'],
'n_estimators': [100,200,50,20],
'max_depth': [2,4,5,10,None],
'min_samples_leaf': [1, 2, 3, 4, 5, 10, 20, 25],
'max_features':['sqrt','log2',None]
}
grid_search_over = GridSearchCV(rfc_over2, param_grid=params, cv=5, scoring='recall', n_jobs=-1,verbose=1)
grid_search_over.fit(X_res2, y_res2)
Fitting 5 folds for each of 960 candidates, totalling 4800 fits
GridSearchCV(cv=5, estimator=RandomForestClassifier(random_state=42), n_jobs=-1,
param_grid={'criterion': ['gini', 'entropy'],
'max_depth': [2, 4, 5, 10, None],
'max_features': ['sqrt', 'log2', None],
'min_samples_leaf': [1, 2, 3, 4, 5, 10, 20, 25],
'n_estimators': [100, 200, 50, 20]},
scoring='recall', verbose=1)In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook. GridSearchCV(cv=5, estimator=RandomForestClassifier(random_state=42), n_jobs=-1,
param_grid={'criterion': ['gini', 'entropy'],
'max_depth': [2, 4, 5, 10, None],
'max_features': ['sqrt', 'log2', None],
'min_samples_leaf': [1, 2, 3, 4, 5, 10, 20, 25],
'n_estimators': [100, 200, 50, 20]},
scoring='recall', verbose=1)RandomForestClassifier(random_state=42)
RandomForestClassifier(random_state=42)
# Wykres ważności cech w odniesieniu do największej bezwzględnej wartości współczynnika regresji. Użyta do tej funkcja wizualizuj sama argument relative= True który powoduje że największej wartość jest przypisywana liczba
# 100 lub minus 100 a pozostałem wartością proporcjonalnie mniejsze liczby.
from yellowbrick.model_selection import FeatureImportances
fig, ax = plt.subplots (figsize=(6, 4))
fi_viz = FeatureImportances (xgb_model)
fi_viz.fit(X, y)
fi_viz.ax.set(title="Ważność 6 cech (XGBoost)", xlabel = "Względna ważność")
[Text(0.5, 1.0, 'Ważność 6 cech (XGBoost)'), Text(0.5, 0, 'Względna ważność')]
raport_XGBoost()
prezycja_czulosc_xgboost()
0.7624161858790544
rownowaga_klas_xgboost()
wykres_blad_prognozaowania_klas_XGboost()
wykres_lime_xgboost()
xgb_reg_model_X_sul=df[['sulphates']].values
xgb_reg_model_y_q=df['alcohol'].values
xgb_reg_model = xgb.XGBRegressor(random_state=123, n_estimators=5, max_depth=7)
xgb_reg_model.fit(xgb_reg_model_X_sul, xgb_reg_model_y_q)
xgb_reg_model_sort_idx= xgb_reg_model_X_sul. flatten().argsort()
lin_regplot (xgb_reg_model_X_sul[xgb_reg_model_sort_idx], xgb_reg_model_y_q[xgb_reg_model_sort_idx], xgb_reg_model)
plt.xlabel('Nieliniowy związek zmiennych [sulphates i alkohol]-trend kształtujący dane')
plt.ylabel('Zawartość alkoholu')
Text(0, 0.5, 'Zawartość alkoholu')
for i in unique_labels:
plt.scatter(X[label==i,0], X[label==i,1], label=i, s=20)
plt.legend()
plt.title('wine groups')
plt.show
<function matplotlib.pyplot.show(close=None, block=None)>
Wszystkie modele zostały przetestowane cross_val_score, natomiast parametry zostały wybrane za pomocą GridSearchCV Metryką, która była dla nas najbardziej istotna jest Recall, która jest intuicyjnie zdolnością klasyfikatora do znalezienia wszystkich pozytywnych próbek. Poniżej tabelka z porównaniem metryk dla modeli.
# ewaluacja modeli
for model in models:
run_model(model, X_train, y_train, skf)
LogisticRegression fbeta: 0.4574, accuracy: 0.8771, time: 0.20085358619689941 DecisionTreeClassifier fbeta: 0.5188, accuracy: 0.8729, time: 0.062445640563964844 RandomForestClassifier fbeta: 0.6261, accuracy: 0.8985, time: 1.8210985660552979 XGBClassifier fbeta: 0.5824, accuracy: 0.8870, time: 0.7411484718322754
print("-----Wyniki f-beta na zbiorze testowym-----")
print("Logistic Regression f-beta: {:.4f}".format(fbeta_LR))
print("Decision Tree f-beta: {:.4f}".format(fbeta_DT))
print("RandomForest f-beta: {:.4f}".format(fbeta_RF))
print("XGBoost f-beta: {:.4f}".format(fbeta_XGB))
-----Wyniki f-beta na zbiorze testowym----- Logistic Regression f-beta: 0.6173 Decision Tree f-beta: 0.5952 RandomForest f-beta: 0.6959 XGBoost f-beta: 0.7071
confusion_matrix_model_the_best()
wykres_ROC_all();
<Figure size 576x432 with 0 Axes>
wykres_porownanie_waznosci_cech()
import shap
shap.initjs()
exp = shap. TreeExplainer (xgr)
vals = exp.shap_values (X_train)
shap.force_plot(exp.expected_value,vals [sample_idx], X_train.iloc[sample_idx],)
#Utworzono obiekt TreeExplainer i wyliczono wartość shap dla próbek. Po utworzeniu obiektu w wyliczeniu wartości utworzona wykres siłowy ułatwiające interpretację prognozowanych wartości
# Wykres siłowy opisujący model regresyjny; poszczególne cechy obniżają wartość bazową z 0,137 do 27
# Base Value to prognozowana wartość bazowa, czerwone cechy to te które podnoszą jakość wszystkie to te które obniżają jakość.
# Można również utworzyć wykres siłowy dla wszystkich próbek i uzyskać w ten sposób obraz działania całego modelu.
# Jeżeli w środowisku Jupyter jest włączo na obsługa skryptów JavaScript, po umieszczeniu nad próbką wskaźnika my szy pojawia się informacja o cechach,
# które wpływają na prognozowany wynik. Poniższy kod tworzy interaktywny wykres:
shap.force_plot( exp.expected_value, vals, X_train)